package edu.siu.math.egut.util;

import org.apache.commons.collections15.list.TreeList;

/**
 * A simple class for trees, with vertices of an arbitrary type, and directed edges, labeled
 * with objects of a second arbitrary type.
 * 
 * @author josephhundley
 *
 * @param <T> type for the vertices of the tree
 * @param <E> type for the edges of the tree
 */
public class Tree<T,E> {
 
    /**
     * @author josephhundley
     *
     * @param <T> type for the vertices. 
     * @param <E> type for the edges.
     */
    public static class Edge<T,E> {
	private T beginning; 
	private T end;
	private E name;
	private Edge(T beginning, T end, E name) {
	    super();
	    this.beginning = beginning;
	    this.end = end;
	    this.name = name;
	}
	
		
    }
    private TreeList<T> vertices;
    private TreeList<Edge<T,E>> edges;
    /**
     * Default constructor.
     * @param vertices a TreeList of Objects to comprise the vertices of the new Tree.
     * @param edges a TreeList of Objects to be the edges.  
     */
    public Tree(TreeList<T> vertices, TreeList<Edge<T, E>> edges) {
	super();
	this.vertices = vertices;
	this.edges = edges;
    }
    
    /**
     * Constructor for empty tree, with no vertices and no edges.
     */
    public Tree(){
	super();
	this.vertices = new TreeList<T>();
	this.edges = new TreeList<Edge<T, E>>();
    }
    
    /**
     * Constructor for simple tree with one vertex and 
     * no edges.
     * @param vertex The unique vertex.
     */
    public Tree(T vertex ){
	super();
	this.vertices = new TreeList<T>();
	vertices.add(vertex);
	this.edges = new TreeList<Edge<T, E>>();
    }
    
    /**
     * Adds a single new vertex and edge to the tree, connected at a specified existing vertex.
     * 
     * @param oldVertex an existing vertex, where the new edge will be attached.
     * @param newVertex an Object to be the new vertex
     * @param nameForNewEdge an Object which will label the new Edge
     * @throws TreeDataException if the new edge is not new or the old edge is not old;  but if the "old" edge is new 
     * AND the "new" edge is old, this method will just assume the user reversed the order and correct it.
     */
    public void add( T oldVertex, T newVertex, E nameForNewEdge) throws TreeDataException{
	if(vertices.contains(newVertex)){
	    if( vertices.contains(oldVertex) &&
		    (!vertices.contains(newVertex)))
		add(newVertex, oldVertex, nameForNewEdge);
	    else 
		throw new TreeDataException("attempt to add new vertex which is not new.");
	}
	if((!(vertices.contains(oldVertex)))){
	    if( vertices.contains(oldVertex) &&
		    (!vertices.contains(newVertex)))
		add(newVertex, oldVertex, nameForNewEdge);
	    else 
		throw new TreeDataException("attempt to old new vertex which is not old.");
	}
	vertices.add(newVertex);
	edges.add(new Edge<T, E>(oldVertex, newVertex, nameForNewEdge));
    }
    
    
}
